﻿using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Windows.Forms;
using DistributedGraph;

namespace CAP.Forms
{
    /// <summary>
    /// Das Hauptfenster.
    /// </summary>
    public partial class MainForm : Form
    {
        #region Attribute
        private static Random random = new Random();

        private Node lastSelectedNode;
        private DistributedGraph.FloodSet.AlgorithmController algorithmFloodSet;
        private DistributedGraph.OptFloodSet.AlgorithmController algorithmOptFloodSet;
        private DistributedGraph.EIGStop.AlgorithmController algorithmEIGStop;
        #endregion Attribute

        #region Methoden
        /// <summary>
        /// Instanzier und Initialisiert das Form.
        /// </summary>
        public MainForm()
        {
            InitializeComponent();
            cbAlgorithm.Items.Add(DistributedGraph.FloodSet.AlgorithmController.NAME);
            cbAlgorithm.Items.Add(DistributedGraph.OptFloodSet.AlgorithmController.NAME);
            cbAlgorithm.Items.Add(DistributedGraph.EIGStop.AlgorithmController.NAME);
            cbAlgorithm.SelectedIndex = 0;
            btnNewGraph_Click(this, new EventArgs());
            ngMain.ExtendNode += new NodeGraph.DrawNodeEvent(ngMain_ExtendNode);
            normalToolTip.SetToolTip(btnAlgoNext, "Nächsten Prozess ausführen");
            normalToolTip.SetToolTip(btnAlgoFRound, "Die nächsten Prozesse bis zum Ende der Runde ausführen.");
            normalToolTip.SetToolTip(btnAlgoFinish, "Alle Prozesse bis zum Ende des Algorithmus ausführen.");
        }

        #region Allgemeine Aktionen
        #region Graph & Algorithm
        /// <summary>
        /// Blendet "Zufällig" ein wenn ein falsche Angabe gemacht wurde.
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void tbNodes_KeyUp(object sender, KeyEventArgs e)
        {
            try
            {
                if (int.Parse(tbNodes.Text) <= 1) throw new Exception();
                lblRandom.Visible = false;
            }
            catch
            {
                lblRandom.Visible = true;
            }
        }

        /// <summary>
        /// Dient zur Erstellung eines neuen Graphen
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void btnNewGraph_Click(object sender, EventArgs e)
        {
            int max = random.Next(2, 10);
            try
            {
                int.TryParse(tbNodes.Text, out max);
                if (max < 2) throw new Exception();
            }
            catch { max = random.Next(2, 10); }
            if (max < 1 || max > 20)
            {
                if (MessageBox.Show(this, "Der Graph sollte zumindest 2 Knoten haben. Mehr als 20 Knoten sind jedoch nicht sinnvoll zu Visualisieren.", "Warnung", MessageBoxButtons.OKCancel, MessageBoxIcon.Warning, MessageBoxDefaultButton.Button2) == System.Windows.Forms.DialogResult.Cancel) return;
                max = Math.Min(max, 100);   // Einfach irgendwie ein Maximum abfedern, da sonst die Anwendung crasht.
            }


            tbFailMax_Leave(this, new EventArgs()); // Um zu prüfen ob der maximale f Wert gültig ist.
            algorithmFloodSet = null;
            algorithmOptFloodSet = null;
            algorithmEIGStop = null;
            if (rbFailAuto.Checked)
            {
                if (cbAlgorithm.SelectedIndex == 0) algorithmFloodSet = new DistributedGraph.FloodSet.AlgorithmController(max, rbMultiValue.Checked ? AlgorithmInput.MultiValue : AlgorithmInput.SingleValue);
                if (cbAlgorithm.SelectedIndex == 1) algorithmOptFloodSet = new DistributedGraph.OptFloodSet.AlgorithmController(max, rbMultiValue.Checked ? AlgorithmInput.MultiValue : AlgorithmInput.SingleValue);
                if (cbAlgorithm.SelectedIndex == 2) algorithmEIGStop = new DistributedGraph.EIGStop.AlgorithmController(max, rbMultiValue.Checked ? AlgorithmInput.MultiValue : AlgorithmInput.SingleValue);
            }
            else
            {
                if (cbAlgorithm.SelectedIndex == 0) algorithmFloodSet = new DistributedGraph.FloodSet.AlgorithmController(max, rbMultiValue.Checked ? AlgorithmInput.MultiValue : AlgorithmInput.SingleValue, int.Parse(tbFailMax.Text));
                if (cbAlgorithm.SelectedIndex == 1) algorithmOptFloodSet = new DistributedGraph.OptFloodSet.AlgorithmController(max, rbMultiValue.Checked ? AlgorithmInput.MultiValue : AlgorithmInput.SingleValue, int.Parse(tbFailMax.Text));
                if (cbAlgorithm.SelectedIndex == 2) algorithmEIGStop = new DistributedGraph.EIGStop.AlgorithmController(max, rbMultiValue.Checked ? AlgorithmInput.MultiValue : AlgorithmInput.SingleValue, int.Parse(tbFailMax.Text));
            }

            if (algorithmFloodSet != null)
            {
                ngMain.Nodes = algorithmFloodSet.Nodes.ToArray();
                algorithmFloodSet.StateChanged += new SimpleAlgorithmEvent<DistributedGraph.FloodSet.Node>(updateAlgorithmState_FloodSet);
                floodSetAlgorithmState.Algorithm = algorithmFloodSet;
                floodSetNodeData.Algorithm = algorithmFloodSet;
            }
            else if (algorithmOptFloodSet != null)
            {
                ngMain.Nodes = algorithmOptFloodSet.Nodes.ToArray();
                algorithmOptFloodSet.StateChanged += new SimpleAlgorithmEvent<DistributedGraph.OptFloodSet.Node>(updateAlgorithmState_OptFloodSet);
                OptFloodSetAlgorithmState.Algorithm = algorithmOptFloodSet;
                OptFloodSetNodeData.Algorithm = algorithmOptFloodSet;
            }
            else if (algorithmEIGStop != null)
            {
                ngMain.Nodes = algorithmEIGStop.Nodes.ToArray();
                algorithmEIGStop.StateChanged += new SimpleAlgorithmEvent<DistributedGraph.EIGStop.Node>(updateAlgorithmState_EIGStop);
                EIGStopAlgorithmState.Algorithm = algorithmEIGStop;
                EIGStopNodeData.Algorithm = algorithmEIGStop;
                // Warnhinweis da EIG seinem Namen gerecht wird.
                // MB Größe: (2 * max + 1) * 4
                // = max für Liste
                // + max für Labels
                // + 1 für den Wert
                // * 4 entsprechend der 32 Bit für einen Integer
                int elements = DistributedGraph.EIGStop.TreeNode.CalculateTreeElementCount(max, rbFailAuto.Checked ? max : int.Parse(tbFailMax.Text));
                if (elements < 0 || elements > 100000) MessageBox.Show(this, "Achtung: Jeder EIGBaum hat bei f = n " + (elements > 0 ? elements.ToString() : "mehr als " + int.MaxValue.ToString()) + " Elemente!\nDies entspricht einer Speichernutzung von mehr als " + Math.Round(((double)(((long)(elements > 0 ? elements : int.MaxValue)) * ((2 * max + 1) * 4))) / 1024 / 1024, 2) + " MB je Baum!", "Hinweis", MessageBoxButtons.OK, MessageBoxIcon.Exclamation);
            }
            updateAlgorithmState();
            if (sender != this) tabControl1.SelectedIndex = 1;
        }

        /// <summary>
        /// Fügt andie Graphen zusätzliche Algorithmenspezifische informationen an.
        /// </summary>
        /// <param name="node">Der aktuelle Knoten</param>
        /// <param name="edi">Die anzufügenden erweiterten Informationen.</param>
        void ngMain_ExtendNode(Node node, NodeGraph.ExtendedDrawingInformation edi)
        {
            // The order has to be changed, because of the inheritage of OptFloodSet:

            if (node is DistributedGraph.OptFloodSet.Node)
            {
                DistributedGraph.OptFloodSet.Node n = (DistributedGraph.OptFloodSet.Node)node;

                edi.TextRightTop = "v =" + n.Value.ToString();
                edi.TextRightTopLow = "  0";
                string menge = "";
                // Acctually the decision isn't a set, but just one value:
                // foreach (int i in n.DecisionResultSet) menge += (menge.Length != 0 ? ", " : "") + i.ToString();
                if (n.IsConsensusComputed)
                    menge += n.DecisionResultSet.ToString();

                edi.TextRightBottom = menge.Length == 0 ? "d=Ø" : "d=" + menge;
            }
            else if (node is DistributedGraph.FloodSet.Node)
            {
                DistributedGraph.FloodSet.Node n = (DistributedGraph.FloodSet.Node)node;

                edi.TextRightTop = "v =" + n.Value.ToString();
                edi.TextRightTopLow = "  0";
                string menge = "";
                // Acctually the decision isn't a set, but just one value:
                // foreach (int i in n.DecisionResultSet) menge += (menge.Length != 0 ? ", " : "") + i.ToString();
                if (n.IsConsensusComputed)
                    menge += n.DecisionResultSet.ToString();

                edi.TextRightBottom = menge.Length == 0 ? "d=Ø" : "d=" + menge;
            }
            else if (node is DistributedGraph.EIGStop.Node)
            {
                DistributedGraph.EIGStop.Node n = (DistributedGraph.EIGStop.Node)node;

                edi.TextRightTop = "v =" + n.Value.ToString();
                edi.TextRightTopLow = "  0";
                string menge = "";
                foreach (int i in n.DecisionResultSet) menge += (menge.Length != 0 ? ", " : "") + i.ToString();
                edi.TextRightBottom = menge.Length == 0 ? "d=Ø" : "d=" + menge;
            }
            edi.ColorRightBottom = node.FailStops ? Color.Red : Color.Black;
            edi.ColorRightTop = edi.ColorRightBottom;
        }

        /// <summary>
        /// Sorgt dafür dass der Eingabebereich für max. fehlerhafte Knoten entsprechend aktiviert/deaktiviert wird.
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void rbFailAuto_CheckedChanged(object sender, EventArgs e)
        {
            tbFailMax.Enabled = rbFailSet.Checked;
        }

        /// <summary>
        /// Sorgt dafür dass der Eingabebereich für max. fehlerhafte Knoten entsprechend aktiviert/deaktiviert wird.
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void rbFailSet_CheckedChanged(object sender, EventArgs e)
        {
            tbFailMax.Enabled = rbFailSet.Checked;
        }

        /// <summary>
        /// Setzt im Fehlerfall nach Beenden des Bearbeitens auf automatisch zurück.
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void tbFailMax_Leave(object sender, EventArgs e)
        {
            if (!rbFailAuto.Checked)
            {
                try
                {
                    int nodes = int.Parse(tbNodes.Text);
                    try
                    {
                        int fails = int.Parse(tbFailMax.Text);
                        if (fails >= nodes || fails < 0) rbFailAuto.Checked = true;
                    }
                    catch { rbFailAuto.Checked = true; }
                }
                catch { rbFailAuto.Checked = true; }
                if (rbFailAuto.Checked) MessageBox.Show(this, "Die Fehlertoleranz wurde auf automatisch zurückgesetzt, da der angegebene Wert nicht anwendbar ist. Dieser muss kleiner als die Knotenanzahl n sein und n muss angegeben sein.", "Hinweis", MessageBoxButtons.OK, MessageBoxIcon.Information);
            }
        }
        #endregion Graphen & Alggorithm
        #region Knotenspezifische Aktionen
        /// <summary>
        /// Gibt an ob weitere Knoten FailStoppen können.
        /// </summary>
        private bool canFailStop
        {
            get
            {
                if (ngMain.Nodes == null) return false;
                int activesLeft = ngMain.Nodes.Length;
                foreach (Node n in ngMain.Nodes) activesLeft -= n.FailStops ? 1 : 0;
                return activesLeft > 1;
            }
        }

        /// <summary>
        /// Wird ausgeführt wenn ein Knoten gewählt / abgewählt wurde.
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="n">Der betreffende Knoten.</param>
        private void ngMain_NodeSelected(object sender, Node n)
        {
            lblNodeSel.Text = n == null ? "- keiner gewählt -" : n.Id.ToString();
            if (n != null)
            {
                lblKAgreement.Visible = !canFailStop && !cbFail.Checked;
                cbFail.Checked = n.FailStops;
                cbFail.Enabled = n.FailStops || canFailStop;
                cbFail.ForeColor = cbFail.Checked ? Color.Red : Color.Black;
                tbValue.Text = (n is DistributedGraph.FloodSet.Node) ? ((DistributedGraph.FloodSet.Node)n).Value.ToString() :
                    ((n is DistributedGraph.OptFloodSet.Node) ? ((DistributedGraph.OptFloodSet.Node)n).Value.ToString() :
                    ((n is DistributedGraph.EIGStop.Node) ? ((DistributedGraph.EIGStop.Node)n).Tree.Value.ToString() : "-"));
                tbValue.Enabled = (n is DistributedGraph.FloodSet.Node && !((DistributedGraph.FloodSet.Node)n).IsStarted) ||
                                  (n is DistributedGraph.OptFloodSet.Node && !((DistributedGraph.OptFloodSet.Node)n).IsStarted) ||
                                  (n is DistributedGraph.EIGStop.Node && !((DistributedGraph.EIGStop.Node)n).IsStarted);
                tabControl1.SelectedIndex = 2;
            }
            else
            {
                cbFail.ForeColor = Color.Black;
                cbFail.Enabled = false;
                lblKAgreement.Visible = false;
                tbValue.Text = "-";
                tbValue.Enabled = false;
            }
            lastSelectedNode = n;
            updateAlgorithmState();
        }

        /// <summary>
        /// Wird ausgeführt wenn FailStop für einen Knoten aktiviert/deaktiviert wurde.
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void cbFail_CheckedChanged(object sender, EventArgs e)
        {
            if (ngMain.SelectedNode != null)
            {
                if (!cbFail.Checked) cbFail.Checked = ngMain.SelectedNode.FailStops; // Lässt sich logischerweise nicht mehr deaktivieren:
                if (canFailStop) ngMain.SelectedNode.FailStops = cbFail.Checked;
                else lblKAgreement.Visible = !cbFail.Checked;
            }
            else
            {
                lblKAgreement.Visible = false;
            }
            cbFail.ForeColor = cbFail.Checked ? Color.Red : Color.Black;
            updateAlgorithmState();
        }

        /// <summary>
        /// Wird gerufen wenn ein Wert über das Textfeld verändert werden soll.
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void tbValue_TextChanged(object sender, EventArgs e)
        {
            try
            {
                if (ngMain.SelectedNode is DistributedGraph.FloodSet.Node) ((DistributedGraph.FloodSet.Node)ngMain.SelectedNode).Value = int.Parse(tbValue.Text);
                if (ngMain.SelectedNode is DistributedGraph.OptFloodSet.Node) ((DistributedGraph.OptFloodSet.Node)ngMain.SelectedNode).Value = int.Parse(tbValue.Text);
                if (ngMain.SelectedNode is DistributedGraph.EIGStop.Node) ((DistributedGraph.EIGStop.Node)ngMain.SelectedNode).Value = int.Parse(tbValue.Text);

                updateAlgorithmState();
            }
            catch
            {
                tbValue.Text = ngMain.SelectedNode is DistributedGraph.FloodSet.Node ? ((DistributedGraph.FloodSet.Node)ngMain.SelectedNode).Value.ToString() :
                              (ngMain.SelectedNode is DistributedGraph.OptFloodSet.Node ? ((DistributedGraph.OptFloodSet.Node)ngMain.SelectedNode).Value.ToString() :
                              (ngMain.SelectedNode is DistributedGraph.EIGStop.Node ? ((DistributedGraph.EIGStop.Node)ngMain.SelectedNode).Value.ToString() : "-"));
                tbValue.SelectAll();
            }
        }
        #endregion Knotenspezifische Aktionen
        #region Algorithmensteuerung
        /// <summary>
        /// Ausführen der nächsten Runde.
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void btnAlgoNext_Click(object sender, EventArgs e)
        {
            if (algorithmFloodSet != null) algorithmFloodSet.NextProcess();
            else if (algorithmOptFloodSet != null) algorithmOptFloodSet.NextProcess();
            else if (algorithmEIGStop != null) algorithmEIGStop.NextProcess();

            // Falls am Anfang ein Knoten selektiert ist und noch bearbeitet werden kann.
            if (lastSelectedNode != null)
            {
                if (lastSelectedNode is DistributedGraph.FloodSet.Node) tbValue.Enabled = !((DistributedGraph.FloodSet.Node)lastSelectedNode).IsStarted;
                if (lastSelectedNode is DistributedGraph.OptFloodSet.Node) tbValue.Enabled = !((DistributedGraph.OptFloodSet.Node)lastSelectedNode).IsStarted;
                if (lastSelectedNode is DistributedGraph.EIGStop.Node) tbValue.Enabled = !((DistributedGraph.EIGStop.Node)lastSelectedNode).IsStarted;
            }
        }

        /// <summary>
        /// Beendet die Runde.
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void btnAlgoFRound_Click(object sender, EventArgs e)
        {
            if (algorithmFloodSet != null) algorithmFloodSet.FinishRound();
            else if (algorithmOptFloodSet != null) algorithmOptFloodSet.FinishRound();
            else if (algorithmEIGStop != null) algorithmEIGStop.FinishRound();

            // Falls am Anfang ein Knoten selektiert ist und noch bearbeitet werden kann.
            if (lastSelectedNode != null)
            {
                if (lastSelectedNode is DistributedGraph.FloodSet.Node) tbValue.Enabled = !((DistributedGraph.FloodSet.Node)lastSelectedNode).IsStarted;
                if (lastSelectedNode is DistributedGraph.OptFloodSet.Node) tbValue.Enabled = !((DistributedGraph.OptFloodSet.Node)lastSelectedNode).IsStarted;
                if (lastSelectedNode is DistributedGraph.EIGStop.Node) tbValue.Enabled = !((DistributedGraph.EIGStop.Node)lastSelectedNode).IsStarted;
            }
        }

        /// <summary>
        /// Beendet den Algorithmus.
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void btnAlgoFinish_Click(object sender, EventArgs e)
        {
            if (algorithmFloodSet != null) algorithmFloodSet.Finish();
            else if (algorithmOptFloodSet != null) algorithmOptFloodSet.Finish();
            else if (algorithmEIGStop != null) algorithmEIGStop.Finish();

            // Falls am Anfang ein Knoten selektiert ist und noch bearbeitet werden kann.
            if (lastSelectedNode != null)
            {
                if (lastSelectedNode is DistributedGraph.FloodSet.Node) tbValue.Enabled = !((DistributedGraph.FloodSet.Node)lastSelectedNode).IsStarted;
                if (lastSelectedNode is DistributedGraph.OptFloodSet.Node) tbValue.Enabled = !((DistributedGraph.OptFloodSet.Node)lastSelectedNode).IsStarted;
                if (lastSelectedNode is DistributedGraph.EIGStop.Node) tbValue.Enabled = !((DistributedGraph.EIGStop.Node)lastSelectedNode).IsStarted;
            }
        }
        #endregion Algorithmensteuerung
        #region Status Updates
        #region EIGStop
        /// <summary>
        /// Dient dazu den aktuellen Stand des EIGStopNodeData-Algorithmus in der Benutzeroberfläche anzuzeigen.
        /// </summary>
        /// <param name="algorithm">Ein EigStop-Algorithmus.</param>
        private void updateAlgorithmState_EIGStop(IAlgorithmController<DistributedGraph.EIGStop.Node> algorithm)
        {
            EIGStopNodeData.Visible = algorithm != null;        // Entfernen und hinzufügen von Controls je nach Algorithmus
            EIGStopAlgorithmState.Visible = algorithm != null;
            if (algorithm == null) return;                      // Wenn der Algorithmus nicht der jetzige ist dann überspringe den Rest.
            DistributedGraph.EIGStop.AlgorithmController algo = (DistributedGraph.EIGStop.AlgorithmController)algorithm;    // Für einfache Arbeit mit algoklasse

            showAlgorithmState(
                algo.Name,
                (algo.Round + 1 <= algo.MaxRounds ? (algo.Round + 1 == 1 && algo.CurrentProcess == 0 ? "Initialisierung" : "Nachrichtenaustausch") : "Abgeschlossen"),
                Math.Min(algo.Round + 1, algo.MaxRounds).ToString(),
                algo.MaxRounds.ToString(),
                (algo.CurrentProcess + 1).ToString(),
                (algo.MaxRounds-1).ToString()
            );

            btnAlgoNext.Enabled = algo.Round + 1 <= algo.MaxRounds;
            btnAlgoFRound.Enabled = btnAlgoNext.Enabled;
            btnAlgoFinish.Enabled = btnAlgoNext.Enabled;

            EIGStopNodeData.Update((DistributedGraph.EIGStop.Node)ngMain.SelectedNode);
            EIGStopAlgorithmState.Update();
        }
        #endregion EIGStop
        #region FloodSet
        /// <summary>
        /// Dient dazu den aktuellen Stand des FloodSet-Algorithmus in der Benutzeroberfläche anzuzeigen.
        /// </summary>
        /// <param name="algorithm">Ein FloodSet-Algorithmus.</param>
        private void updateAlgorithmState_FloodSet(IAlgorithmController<DistributedGraph.FloodSet.Node> algorithm)
        {
            floodSetNodeData.Visible = algorithm != null;               // Entfernen und hinzufügen von Controls je nach Algorithmus
            floodSetAlgorithmState.Visible = algorithm != null;
            if (algorithm == null) return;                              // Wenn der Algorithmus nicht der jetzige ist dann überspringe den Rest.
            DistributedGraph.FloodSet.AlgorithmController algo = (DistributedGraph.FloodSet.AlgorithmController)algorithm;  // Für einfache Arbeit mit Algoklasse.

            // Implement here
            showAlgorithmState(
                algo.Name,
                (algo.Round + 1 <= algo.MaxRounds ? (algo.Round + 1 == 1 && algo.CurrentProcess == 0 ? "Initialisierung" : "Nachrichtenaustausch") : "Abgeschlossen"),
                Math.Min(algo.Round + 1, algo.MaxRounds).ToString(),
                algo.MaxRounds.ToString(),
                (algo.CurrentProcess + 1).ToString(),
                (algo.MaxRounds - 1).ToString()
            );

            btnAlgoNext.Enabled = algo.Round + 1 <= algo.MaxRounds;
            btnAlgoFRound.Enabled = btnAlgoNext.Enabled;
            btnAlgoFinish.Enabled = btnAlgoNext.Enabled;

            floodSetNodeData.Update((DistributedGraph.FloodSet.Node)ngMain.SelectedNode);
            floodSetAlgorithmState.Update();
        }
        #endregion FloodSet
        #region OPTFloodSet
        /// <summary>
        /// Dient dazu den aktuellen Stand des OptFloodSet-Algorithmus in der Benutzeroberfläche anzuzeigen.
        /// </summary>
        /// <param name="algorithm">Ein OptFloodSet-Algorithmus.</param>
        private void updateAlgorithmState_OptFloodSet(IAlgorithmController<DistributedGraph.OptFloodSet.Node> algorithm)
        {
            OptFloodSetNodeData.Visible = algorithm != null;            // Entfernen und hinzufügen von Controls je nach Algorithmus
            OptFloodSetAlgorithmState.Visible = algorithm != null;
            if (algorithm == null) return;                              // Wenn der Algorithmus nicht der jetzige ist dann überspringe den Rest.
            DistributedGraph.OptFloodSet.AlgorithmController algo = (DistributedGraph.OptFloodSet.AlgorithmController)algorithm;    // Für einfache Arbeit mit Algoklasse.

            // Implement here
            showAlgorithmState(
                algo.Name,
                (algo.Round + 1 <= algo.MaxRounds ? (algo.Round + 1 == 1 && algo.CurrentProcess == 0 ? "Initialisierung" : "Nachrichtenaustausch") : "Abgeschlossen"),
                Math.Min(algo.Round + 1, algo.MaxRounds).ToString(),
                algo.MaxRounds.ToString(),
                (algo.CurrentProcess + 1).ToString(),
                (algo.MaxRounds - 1).ToString()
            );

            btnAlgoNext.Enabled = algo.Round + 1 <= algo.MaxRounds;
            btnAlgoFRound.Enabled = btnAlgoNext.Enabled;
            btnAlgoFinish.Enabled = btnAlgoNext.Enabled;

            OptFloodSetNodeData.Update((DistributedGraph.OptFloodSet.Node)ngMain.SelectedNode);
            OptFloodSetAlgorithmState.Update();
        }
        #endregion OPTFloodSet
        /// <summary>
        /// Dient dazu den aktuellen Stand des aktuellen Algorithmus in der Benutzeroberfläche anzuzeigen.
        /// Dabei wird hier die Verteilung auf den jeweiligen Algorithmusstatus vorgenommen.
        /// </summary>
        private void updateAlgorithmState()
        {
            updateAlgorithmState_FloodSet(algorithmFloodSet);
            updateAlgorithmState_OptFloodSet(algorithmOptFloodSet);
            updateAlgorithmState_EIGStop(algorithmEIGStop);
            ngMain.Invalidate();
        }

        /// <summary>
        /// Zeigt den Algorithmusstatus in der Benutzeroberfläche an.
        /// </summary>
        /// <param name="name">Der Name des Algorithmus.</param>
        /// <param name="phase">Die Phase des Algorithmus.</param>
        /// <param name="round">Die Runde in der sich der Algorithmus befindet.</param>
        /// <param name="maxRound">Die maximale Rundenanzahl.</param>
        /// <param name="step">Der aktuelle Prozess/Teilschritt.</param>
        /// <param name="f">Die Fehlertoleranz.</param>
        private void showAlgorithmState(string name, string phase, string round, string maxRound, string step, string f)
        {
            lblAlgo.Text = name;
            lblAbschnitt.Text = phase;
            lblProgress.Text = "Runde: " + round + "/" + maxRound + " - Schritt: " + step;
            lblF.Text = "( f=" + f + " )";

            sblAlgorithm.Text = "Algorithmus: " + name;
            sblPhase.Text = "Abschnitt: " + phase;
            sblRound.Text = "Runde: " + round + "/" + maxRound;
            sblProcess.Text = "Schritt: " + step;
        }
        #endregion Status Updates
        #endregion Allgemeine Aktionen
        #endregion Methoden
    }
}
